package net.sf.rose.util;

import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * 类说明：AES加解密算法
 * 
 * @author fengjian E-mail: 9110530@qq.com
 * @version 创建时间：2017年6月16日 下午3:51:16
 */
public class AesEncrypt {

	/**
	 * 加密
	 * 
	 * @param content 需要加密的内容
	 * @param key     加密密码
	 * @param md5Key  是否对key进行md5加密
	 * @param iv      加密向量
	 * @return 加密后的字节数据
	 */
	public byte[] encrypt(byte[] content, byte[] key, boolean md5Key, byte[] iv) {
		try {
			if (md5Key) {
				MessageDigest md = MessageDigest.getInstance("MD5");
				key = md.digest(key);
			}
			SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding"); // "算法/模式/补码方式"
			IvParameterSpec ivps = new IvParameterSpec(iv);// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
			cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivps);
			return cipher.doFinal(content);
		} catch (Exception e) {
			throw new RuntimeException("加密算法失败" + e.getMessage(), e);
		}
	}

	public byte[] decrypt(byte[] content, byte[] key, boolean md5Key, byte[] iv) {
		try {
			if (md5Key) {
				MessageDigest md = MessageDigest.getInstance("MD5");
				key = md.digest(key);
			}
			SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding"); // "算法/模式/补码方式"
			IvParameterSpec ivps = new IvParameterSpec(iv);// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
			cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivps);
			return cipher.doFinal(content);
		} catch (Exception e) {
			throw new RuntimeException("解密算法执行失败:" + e.getMessage(), e);
		}
	}

	/*
	 * 01 算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
	 * 02 AES/CBC/NoPadding 16 不支持
	 * 03 AES/CBC/PKCS5Padding 32 16
	 * 04 AES/CBC/ISO10126Padding 32 16
	 * 05 AES/CFB/NoPadding 16 原始数据长度
	 * 06 AES/CFB/PKCS5Padding 32 16
	 * 07 AES/CFB/ISO10126Padding 32 16
	 * 08 AES/ECB/NoPadding 16 不支持
	 * 09 AES/ECB/PKCS5Padding 32 16
	 * 10 AES/ECB/ISO10126Padding 32 16
	 * 11 AES/OFB/NoPadding 16 原始数据长度
	 * 12 AES/OFB/PKCS5Padding 32 16
	 * 13 AES/OFB/ISO10126Padding 32 16
	 * 14 AES/PCBC/NoPadding 16 不支持
	 * 15 AES/PCBC/PKCS5Padding 32 16
	 * 16 AES/PCBC/ISO10126Padding 32 16
	 * 
	 * CryptoJS supports the following padding schemes:
	 * 
	 * Pkcs7 (the default)
	 * Iso97971
	 * AnsiX923
	 * Iso10126
	 * ZeroPadding
	 * NoPadding
	 */

	public static void main(String[] args) throws Exception {
		AesEncrypt aes = new AesEncrypt();
		byte[] aesKey = "abcdefgabcdefg12".getBytes("UTF-8");
		byte[] bytes = "我爱你".getBytes();

		// 以下是对数据进行加密
		bytes = aes.encrypt(bytes, aesKey, false, aesKey);
		String enstr = Base64.encodeBase64String(bytes);
		System.out.println("加密后：" + enstr);
		// 以上是对数据进行加密

		// 以下是对数据进行解密
		enstr = "SLXdryKdhfkh02dvKsuiNQ==";
		System.out.println("加密后：" + enstr);
		bytes = Base64.decodeBase64(enstr);
		bytes = aes.decrypt(bytes, aesKey, false, aesKey);
		// 以上是对数据进行解密

		String jsonStr = new String(bytes, "UTF-8");
		System.out.println("解密后：" + jsonStr);
	}

}
